
#include <stdio.h>
#include "../../src/purg.h"

extern "C"
{

int *init_rng ( int , int gennum , int , int seed , int )
{
	purg::parallel_gen *ret_val = new purg::parallel_gen ( seed , 0 , gennum );
	return reinterpret_cast<int *> ( ret_val );
}

double  get_rn_dbl ( int *igenptr )
{
	purg::parallel_gen *gen = reinterpret_cast<purg::parallel_gen *> ( igenptr );
	double ret_val;
	gen->get ( ret_val , 0. , 1. );
	return ret_val;
}

int  get_rn_int ( int *igenptr )
{
	purg::parallel_gen *gen = reinterpret_cast<purg::parallel_gen *> ( igenptr );
	int ret_val;
	gen->get ( ret_val , 0 , (1<<31)-1 );
	return ret_val;
}

float get_rn_flt ( int *igenptr )
{
	purg::parallel_gen *gen = reinterpret_cast<purg::parallel_gen *> ( igenptr );
	float ret_val;
	gen->get ( ret_val , 0. , 1. );
	return ret_val;
}

int  spawn_rng ( int *igenptr , int nspawned , int ***newgens , int )
{
	if ( nspawned < 0 )
		nspawned = 1;

	*newgens = new int *[nspawned];
	int id = get_rn_int ( igenptr );
	int seed = get_rn_int ( igenptr );
	for ( int i = 0 ; i != nspawned ; i++ )
	{
		(*newgens)[i] = init_rng ( 0 , id+i , 0 , seed , 0 );
	}
	return nspawned;
}

int  free_rng ( int *igenptr )
{
	purg::parallel_gen *gen = reinterpret_cast<purg::parallel_gen *> ( igenptr );
	delete gen;
	return 1;
}

int  pack_rng ( int *igenptr , char **buf )
{
	purg::parallel_gen *_purg = reinterpret_cast<purg::parallel_gen *> ( igenptr );
	purg::buffer  &state_buf = *(_purg->get_gen1_state()._buffer);
	*buf = new char [ 2*sizeof(int) + 2*sizeof(size_t) + state_buf.size() ];
	int *len = reinterpret_cast<int *> ( *buf );
	int *seed_ptr = reinterpret_cast<int *> ( (*buf) + sizeof(int) );
	size_t *id = reinterpret_cast<size_t *> ( (*buf) + 2*sizeof(int) );
	size_t *iteration = reinterpret_cast<size_t *> ( (*buf) + 2*sizeof(int) + sizeof ( size_t ));
	unsigned char *tbuf = reinterpret_cast<unsigned char *> ( (*buf) + 2*sizeof(int) + 2*sizeof ( size_t ));
	state_buf.copyTo ( reinterpret_cast<void *> ( tbuf ) , 0 , 0 , state_buf.size() );
	*len = _purg->get_gen1_state()._length;
	*seed_ptr = *(_purg->get_gen1_state()._seed_ptr);
	*id = *(_purg->get_gen1_state()._id);
	*iteration = *(_purg->get_gen1_state()._iteration);
	return 1;
}

int  unpack_rng ( int *igenptr , char **buf )
{
	purg::parallel_gen *_purg = reinterpret_cast<purg::parallel_gen *> ( igenptr );
	purg::buffer  &state_buf = *(_purg->get_gen1_state()._buffer);
	*buf = new char [ 2*sizeof(int) + 2*sizeof(size_t) + state_buf.size() ];
	int *len = reinterpret_cast<int *> ( *buf );
	int *seed_ptr = reinterpret_cast<int *> ( (*buf) + sizeof(int) );
	size_t *id = reinterpret_cast<size_t *> ( (*buf) + 2*sizeof(int) );
	size_t *iteration = reinterpret_cast<size_t *> ( (*buf) + 2*sizeof(int) + sizeof ( size_t ));
	unsigned char *tbuf = reinterpret_cast<unsigned char *> ( (*buf) + 2*sizeof(int) + 2*sizeof ( size_t ));
	memcpy ( &(state_buf[0]) , tbuf , state_buf.size() );
	_purg->get_gen1_state()._length = *len;
	*(_purg->get_gen1_state()._seed_ptr) = *seed_ptr;
	*(_purg->get_gen1_state()._id) = *id;
	*(_purg->get_gen1_state()._iteration) = *iteration;
	return 1;
}

int get_seed_rng ( int *gen )
{
	return 0;
}

int print_rng ( int *igen )
{
	printf ( "\nSPRNG interface to PURG\n" );
}

}
